package com.mano.mall.service.seckill.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.util.concurrent.RateLimiter;
import com.mano.mall.api.seckill.SecKillService;
import com.mano.mall.common.base.BaseApiService;
import com.mano.mall.common.base.BaseResponse;
import com.mano.mall.common.token.GenerateToken;
import com.mano.mall.common.utils.RedisUtil;
import com.mano.mall.service.mapper.SeckillMapper;
import com.mano.mall.service.mapper.entity.SeckillEntity;
import com.mano.mall.service.mq.producer.SecKillProducer;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * @Author: zj
 * @Description:
 * @Date: Created in 11:14 2020/11/10
 * @Modified By:
 */
@RestController
@Slf4j
public class SecKillServiceImpl extends BaseApiService<JSONObject> implements SecKillService {

//    @Autowired
//    private OrderMapper orderMapper;

    @Autowired
    private SeckillMapper seckillMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private GenerateToken generateToken;

    @Autowired
    private SecKillProducer secKillProducer;

    @Override
    @HystrixCommand(fallbackMethod = "defaultCallBackMethod")
    public BaseResponse<JSONObject> secKill(String phone, Long seckillId) {

        // 1.验证参数
        if (StringUtils.isEmpty(phone)) {
            return setResultError("手机号码不能为空!");
        }
        if (seckillId == null) {
            return setResultError("库存id不能为空!");
        }

        // 注释原因： 限流的方案很多，比如nginx,hystrix,Guava的令牌桶等等，逻辑不会放在这里执行，
//        Boolean resultNx = redisUtil.setNx(phone, seckillId + "", 10l);
//        if (!resultNx) {
//            return setResultError("该用户操作过于频繁,请稍后重试!");
//        }
        // 2.根据库存id查询商品是否存在
        // 注释原因，如果能从下面拿到redis的库存令牌，则商品肯定存在，拿不到就肯定不存在
//        SeckillEntity seckillEntity = seckillMapper.findBySeckillId(seckillId);
//        if (seckillEntity == null) {
//            return setResultError("该商品信息不存在!");
//        }

//        // 3.对库存的数量实现减去1
//        Long version = seckillEntity.getVersion();
//        int inventoryDeduction = seckillMapper.optimisticVersionSeckill(seckillId, version);
//        if (!toDaoResult(inventoryDeduction)) {
//            log.info(">>>>phone:{},seckillId:{},秒杀失败!", phone, seckillId);
//            return setResultError("系统错误!");
//        }
//        log.info(">>>>phone:{},seckillId:{},扣库存成功!", phone, seckillId);
//
//        // 4.添加秒杀成功订单
//        OrderEntity orderEntity = new OrderEntity();
//        orderEntity.setSeckillId(seckillId);
//        orderEntity.setUserPhone(phone);
//        int insertOrder = orderMapper.insertOrder(orderEntity);
//        if (!toDaoResult(insertOrder)) {
//            return setResultError("系统错误!");
//        }
//        log.info(">>>>phone:{},seckillId:{},秒杀成功", phone, seckillId);
//
//        return setResultSuccess("恭喜你,秒杀成功!");

        String seckillToken = generateToken.getListKeyToken(seckillId + "");
        if (StringUtils.isEmpty(seckillToken)) {
            log.info(">>>seckillId:{}, 亲，该秒杀已经售空，请下次再来!", seckillId);
            return setResultError("亲，该秒杀已经售空，请下次再来!");
        }

        // 3.获取到秒杀token之后，异步放入mq中实现修改商品的库存
        sendSeckillMsg(seckillId, phone);
        return setResultSuccess("正在排队中.......");

    }

    /**
     * 获取到秒杀token之后，异步放入mq中实现修改商品的库存
     */
    @Async
     void sendSeckillMsg(Long seckillId, String phone) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("seckillId", seckillId);
        jsonObject.put("phone", phone);
        secKillProducer.send(jsonObject);
    }

    @Override
    public BaseResponse<JSONObject> addSeckillToken(Long seckillId) {
        // 1.验证参数
        if (seckillId == null) {
            return setResultError("商品库存id不能为空!");
        }

        SeckillEntity seckillEntity = seckillMapper.findBySeckillId(seckillId);
        if (seckillEntity == null) {
            return setResultError("商品信息不存在!");
        }
        long tokenQuantity = seckillEntity.getInventory();
        if(tokenQuantity==0){
            return setResultError("商品无货，不能秒杀!");
        }

        // 2.使用多线程异步生产令牌
        createSeckillToken(seckillId, tokenQuantity);
        return setResultSuccess("令牌正在生成中.....");
    }

    @Async
    void createSeckillToken(Long seckillId, Long tokenQuantity) {
        generateToken.createListToken("seckill_", seckillId + "", tokenQuantity);
    }


}
